/**
 * @file feiyin_ir02f.c
 * @author Quincy(wangqyfm@foxmail.com)
 * @brief Feiyin Cloud IR02F
 * @version 0.1
 * @date 2021-05-03
 *
 * @copyright Copyright (c) 2021 Quincy(wangqyfm@foxmail.com)
 *
 * SPDX-License-Identifier: Apache-2.0
 */

#define DT_DRV_COMPAT feiyin_ir02f

#include "feiyin_ir02f.h"

#include <errno.h>
#include <arch/cpu.h>
#include <init.h>
#include <kernel.h>
#include <stdlib.h>
#include <string.h>
#include <drivers/uart.h>
#include <logging/log.h>

LOG_MODULE_REGISTER(IR02F, CONFIG_SENSOR_LOG_LEVEL);

#define DEFAULT_ADDR 0xfa  /**< 默认地址 */
#define FRAME_HDR    0xfd  /**< 帧头 */
#define FRAME_TRIL   0xdf  /**< 帧尾 */

#define IR02F_FUNC_REC      0x01  /**< 学习 */
#define IR02F_FUNC_TRANS    0x02  /**< 发射 */
#define IR02F_FUNC_SET_BAUD 0x03  /**< 修改波特率 */
#define IR02F_FUNC_SET_ADDR 0x04  /**< 修改地址 */
#define IR02F_FUNC_CLEAR    0x05  /**< 清除全部键码 */

#define RESPONSE_RECORDING   0xa1 /** 进入学习 */
#define RESPONSE_RECORDED    0xa2 /** 学习成功 */
#define RESPONSE_SET_BAUD    0xa4 /** 修改波特率成功 */
#define RESPONSE_SET_ADDR    0xa5 /** 修改地址成功 */
#define RESPONSE_CLEAR       0xa6 /** 清除完成 */
#define RESPONSE_TRANSMITTED 0xf1 /** 发射完成 */

#define DEFAULT_TIMEOUT_MSEC 2000

#define IS_INVALID(code) (((code) < 1) || ((code) > 0xff))

struct ir02f_data
{
    const struct device * uart_dev;
    uint8_t t_buff[5];
};
/**
 * @brief IR02F 发射
 * 
 * @param dev IR02F
 * @param code 发射的键值，范围 1~255
 * @return 错误码
 */
static int _ir02f_transmit(const struct device * dev, int code)
{
    char ch;
    int rc = 0;
    int msec = 0;
    struct ir02f_data * drv_data = dev->data;

    if (IS_INVALID(code))
    {
        return -EINVAL;
    }

    drv_data->t_buff[0] = DEFAULT_ADDR;
    drv_data->t_buff[1] = FRAME_HDR;
    drv_data->t_buff[2] = IR02F_FUNC_TRANS;
    drv_data->t_buff[3] = code & 0xff;
    drv_data->t_buff[4] = FRAME_TRIL;

    for(int i = 0; i < sizeof(drv_data->t_buff); ++i)
    {
        uart_poll_out(drv_data->uart_dev, drv_data->t_buff[i]);
    }

    do
    {
        rc = uart_poll_in(drv_data->uart_dev, &ch);

        if (rc == 0 && ch == RESPONSE_TRANSMITTED)
        {
            break;
        }

        msec += 10;
        k_sleep(K_MSEC(10));
    } while (msec < DEFAULT_TIMEOUT_MSEC);
    
    return rc;
}

/**
 * @brief IR02F 学习
 * 
 * @param dev IR02F
 * @param code 需要学习的键值，范围 1~255
 * @return 错误码
 */
static int _ir02f_copy(const struct device * dev, int code)
{
    char ch;
    int rc = 0;
    int msec = 0;
    struct ir02f_data * drv_data = dev->data;

    if (IS_INVALID(code))
    {
        return -EINVAL;
    }

    drv_data->t_buff[0] = DEFAULT_ADDR;
    drv_data->t_buff[1] = FRAME_HDR;
    drv_data->t_buff[2] = IR02F_FUNC_REC;
    drv_data->t_buff[3] = code & 0xff;
    drv_data->t_buff[4] = FRAME_TRIL;

    for(int i = 0; i < sizeof(drv_data->t_buff); ++i)
    {
        uart_poll_out(drv_data->uart_dev, drv_data->t_buff[i]);
    }

    do
    {
        rc = uart_poll_in(drv_data->uart_dev, &ch);

        if (rc == 0 && ch == RESPONSE_RECORDED)
        {
            break;
        }

        msec += 10;
        k_sleep(K_MSEC(10));
    } while (msec < DEFAULT_TIMEOUT_MSEC);
    
    return rc;
}

static int ir02f_init(const struct device * dev)
{
    struct ir02f_data * drv_data = dev->data;
    struct uart_config cfg;

    drv_data->uart_dev = device_get_binding(DT_INST_BUS_LABEL(0));

    if (!drv_data->uart_dev)
    {
        LOG_DBG("uart device is not found: %s",
                DT_INST_BUS_LABEL(0));
        return -EINVAL;
    }
    
    uart_config_get(drv_data->uart_dev, &cfg);
    LOG_WRN("Bard: %d", cfg.baudrate);

    cfg.baudrate = 115200;

    uart_configure(drv_data->uart_dev, &cfg);

    return 0;
}

static struct ir02f_data ir02f_data;

const static struct ir02f_driver_api ir02f_api = {
    .transmit = _ir02f_transmit,
    .copy = _ir02f_copy,
};

#define INIT_PRIORITY 55

DEVICE_DT_INST_DEFINE(0, &ir02f_init, device_pm_control_nop,
                      &ir02f_data, NULL, POST_KERNEL,
                      INIT_PRIORITY, &ir02f_api);

// 
